#include "ask_encode.h"
#include "format.h"
#include "utils.h"

#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <string.h>

int main(int argc,char **argv)
{
	if(argc!=2) die("Usage: %s file.dat",argv[0]);

	FILE *in=open_file(argv[1],"rb",stdin,"Couldn't open file \"%s\".\n");

	fseek(in,0,SEEK_END);
	int length=ftell(in);
	fseek(in,0,SEEK_SET);

	u_int8_t bytes[length];
	fread(bytes,1,length,in);
	if(in!=stdin) fclose(in);

	check_errors(bytes,length,argv[1],1);

	u_int8_t *file=bytes+6;
	int size=file_size(bytes,length)-6;

	if(size<32) die("File too short.");
	if(file[0]!=3) die("Unknown file format.");

	int width=file[2]*32;
	int height=file[3]*32;
	if(height==0) height=24;

	int mapoffs=file[12]|(file[13]<<8);
	if(mapoffs+2>size) die("File too short");

	int filemapsize=file[mapoffs]|(file[mapoffs+1]<<8);
	int filemapend=mapoffs+4+filemapsize;
	if(filemapend>size) die("File too short");

	int mapsize=width*height;
	int map[mapsize];
	memset(map,'?',sizeof(map));

	int filepos=mapoffs+4;
	int mappos=0;

	for(;;)
	{
		if(filepos>=filemapend) die("Input file overrun");

		int opcode=file[filepos++];

		if(opcode==0) { if(filepos==filemapend) break; }
		else if(opcode>=0x01&&opcode<=0x1f)
		{
			for(int i=0;i<opcode;i++)
			{
				if(filepos>=filemapend) die("Input file overrun");
				if(mappos>=mapsize) die("Map data overrun");
				map[mappos++]=file[filepos++];
			}
		}
		else if(opcode>=0x20&&opcode<=0x3f)
		{
			if(filepos>=filemapend) die("Input file overrun");
			int argument=file[filepos++];

			int count=argument+((opcode&1)<<8)+2;
			int repeatsize=((opcode&0x1e)>>1)+1;
			if(repeatsize>mappos) die("Map data underrun");

			int repeatstart=mappos-repeatsize;

			for(int i=0;i<count;i++)
			{
				if(mappos>=mapsize) die("Map data overrun");
				map[mappos++]=map[repeatstart+i%repeatsize];
			}
		}
		else if(opcode>=0x40&&opcode<=0x7f)
		{
			if(filepos>=filemapend) die("Input file overrun");
			int argument=file[filepos++];

			int count=(argument&0x0f)+2;
			int offset=((opcode&0x3f)<<4)+((argument&0xf0)>>4)+1;
			if(offset>mappos) die("Map data underrun");

			for(int i=0;i<count;i++)
			{
				if(mappos>=mapsize) die("Map data overrun");
				map[mappos]=map[mappos-offset];
				mappos++;
			}
		}
		else if(opcode>=0x80&&opcode<=0xff)
		{
			int count=(opcode&0x03)+1;
			int offset=((opcode&0x7c)>>2)+1;
			if(offset>mappos) die("Map data underrun");

			for(int i=0;i<count;i++)
			{
				if(mappos>=mapsize) die("Map data overrun");
				map[mappos]=map[mappos-offset];
				mappos++;
			}
		}
	}

	if(mappos!=mapsize) die("Not enough map data found (%d of %d).",mappos,mapsize);

	printf(",");
	for(int x=0;x<width;x++) printf("-");
	printf(".\n");

	for(int y=0;y<height;y++)
	{
		printf("|");
		for(int x=0;x<width;x++)
		{
			int tile=map[x+y*width];
			if(tile==0) printf(" ");
			else if(tile>9||tile<0) printf("?");
			else printf("%d",tile);
		}
		printf("|\n");
	}

	printf("`");
	for(int x=0;x<width;x++) printf("-");
	printf("´\n");
}
